# class Person:
#  def set_name(self, name):
#   self.name = name
#  def get_name(self):
#   return self.name
#  def greet(self):
#   print("Hello, world! I'm {}.".format(self.name))
#
# foo = Person()
# bar = Person()
# foo.set_name('Luke Skywalker')
# foo.set_name('鲟鱼')
# bar.set_name('Anakin Skywalker')
# bar.set_name('美团丽人')
# foo.greet()#只会输出最近set_name的，如果foo是一个Person实例,可以理解成Person.greet（foo）
# print(bar.get_name())#只会输出最近set_name的

#需要理解self是什么——————对foo调用set_name和greet时，foo都会作为第一个参数自动传递给它们。我将这个参数命名为self


#子类扩展了超类的定义。要指定超类，可在class语句中的类名后加上超类名，并将其用圆括号括起
class Filter:
 def init(self):
  self.blocked = []
 def filter(self, sequence):#sequence序列
  return [x for x in sequence if x not in self.blocked]

class SPAMFilter(Filter): # SPAMFilter是Filter的子类
 def init(self): # 重写超类Filter的方法init
  self.blocked = ['SPAM']

f = Filter()
f.init()
print(f.filter([1, 2, 3]))
#想要得到输出32~34行都要执行，34中的self.blocked需要init()来实现
#在这里输出的是[1, 2, 3]
print(f.filter([3, 4, 5]))
#在这里输出的是[3, 4, 5]，与上面类似都是输出最新的

s = SPAMFilter()
s.init()
print(s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM']))
#这里输出是['eggs', 'bacon']
#Filter类的用途在于可用作其他类（如将'SPAM'从序列中过滤掉的SPAMFilter类）的基类（超类）。
#第29行以提供新定义的方式重写了Filter类中方法init的定义，决定了需要过滤什么
#子类SPAMFilter类直接从Filter类继承了方法filter的定义，因此无需重新编写其定义

#其他关于继承的知识
#要确定一个类是否是另一个类的子类，可使用内置方法issubclass
print(issubclass(SPAMFilter, Filter)) #True
print(issubclass(Filter, SPAMFilter)) #False
#如果你有一个类，并想知道它的基类，可访问其特殊属性__bases__。
print(SPAMFilter.__bases__)#(<class '__main__.Filter'>,)
print(Filter.__bases__)#(<class 'object'>,)
#要确定对象是否是特定类的实例，可使用isinstance
s = SPAMFilter()
print(isinstance(s, SPAMFilter))#True
print(isinstance(s, SPAMFilter))#True,属于父类也会输出为True
print(isinstance(s, str))#False
#如果你要获悉对象属于哪个类，可使用属性__class__
print(s.__class__)#<class '__main__.SPAMFilter'>

#如何继承多个类
class Calculator:
 def calculate(self, expression):
  self.value = eval(expression) #eval() 函数用来执行一个字符串表达式，并返回表达式的值。
class Talker:
 def talk(self):
  print('Hi, my value is', self.value)
class TalkingCalculator(Calculator, Talker):  #子类TalkingCalculator本身无所作为，其所有的行为都是从超类那里继承的
 pass

tc = TalkingCalculator()
tc.calculate('1 + 2 * 3') #'1 + 2 * 3'属于expression表达式
tc.talk() #输出语句

#书中对一些的理解，有助于理解上面的代码
#对象：对象由属性和方法组成。属性不过是属于对象的变量
#self：方法是存储在属性中的函数。相比于其他函数，（关联的）方法有一个不同之处，那就是它总是将其所属的对象作为第一个参数，而这个参数通常被命名为self
#object.method(arguments)——对象方法（参数）
#类：
# （1）类表示一组（或一类）对象，而每个对象都属于特定的类。
# （2）类的主要任务是定义其实例将包含的方法

#多态：多态指的是能够同样地对待不同类型和类的对象，即无需知道对象属于哪个类就可调用其方法——可对不同类型的对象执行相同的操作
print('abc'.count('a') )
print([1, 2, 'a'].count('a'))
#如果有一个变量x，你无需知道它是字符串还是列表就能调用方法count：只要你向这个方法提供一个字符作为参数，它就能正常运行。

# callable(object) 判断对象是否是可调用的（如是否是函数或方法）
# getattr(object,name[,default]) 获取属性的值，还可提供默认值
# hasattr(object, name) 确定对象是否有指定的属性
# isinstance(object, class) 确定对象是否是指定类的实例
# issubclass(A, B) 确定A是否是B的子类
# random.choice(sequence) 从一个非空序列中随机地选择一个元素
# setattr(object, name, value) 将对象的指定属性设置为指定的值
# type(object) 返回对象的类型